/***********************************************************************
**
**  REBOL [R3] Language Interpreter and Run-time Environment
**
**  Copyright 2012 REBOL Technologies
**  REBOL is a trademark of REBOL Technologies
**
**  Licensed under the Apache License, Version 2.0 (the "License");
**  you may not use this file except in compliance with the License.
**  You may obtain a copy of the License at
**
**  http://www.apache.org/licenses/LICENSE-2.0
**
**  Unless required by applicable law or agreed to in writing, software
**  distributed under the License is distributed on an "AS IS" BASIS,
**  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
**  See the License for the specific language governing permissions and
**  limitations under the License.
**
************************************************************************
**
**  Title: Draw Dialect Backend
**  Author: Cyphre, Carl
**  Purpose: Evaluates DRAW commands; calls graphics functions.
**
************************************************************************
**
**  NOTE to PROGRAMMERS:
**
**    1. Keep code clear and simple.
**    2. Document unusual code, reasoning, or gotchas.
**    3. Use same style for code, vars, indent(4), comments, etc.
**    4. Keep in mind Linux, OS X, BSD, big/little endian CPUs.
**    5. Test everything, then test it again.
**
***********************************************************************/

#include <stdlib.h>
#include <string.h>
#include <math.h>

#include "reb-host.h"
#include "host-lib.h"
#include "reb-types.h"
#include "reb-value.h"
#include "reb-dialect.h"
#include "words-draw.h"	// Auto-generated by gen-draw-words.r
#include "rebol-lib.h"

#define ENABLE_DRAW
#include "agg-draw.h"

//#define AGGC ((agg_graphics*)context)

#define ARG_LOGIC(n)	VAL_LOGIC(arg+n)
#define ARG_INTEGER(n)	VAL_INT32(arg+n)
#define ARG_STRING(n)	VAL_STRING(arg+n)
#define ARG_PAIR(n)		VAL_PAIR(arg+n)
#define ARG_DECIMAL(n)	VAL_DECIMAL(arg+n)
#define ARG_TUPLE(n)	VAL_TUPLE(arg+n)
#define ARG_WORD(n)		VAL_WORD(arg+n)

#define ARG_OBJECT(n)	VAL_SERIES(arg+n)  // temp
#define ARG_IMAGE(n)	VAL_SERIES(arg+n)  // temp
#define ARG_BLOCK(n)	VAL_SERIES(arg+n)

#define ARG_WORDS(n,s,e) ((ARG_WORD(n)>=s && ARG_WORD(n)<=e) ? ARG_WORD(n)-s : 0)

enum SHAPE_Lit_Words {
	DW_ARC_LIT = DW_ARC + 0x1000,
	DW_CURV_LIT = DW_CURV + 0x1000,
	DW_CURVE_LIT = DW_CURVE + 0x1000,
	DW_HLINE_LIT = DW_HLINE + 0x1000,
	DW_LINE_LIT = DW_LINE + 0x1000,
	DW_MOVE_LIT = DW_MOVE + 0x1000,
	DW_QCURV_LIT = DW_QCURV + 0x1000,
	DW_QCURVE_LIT = DW_QCURVE + 0x1000,
	DW_VLINE_LIT = DW_VLINE + 0x1000
};

/***********************************************************************
**
*/	REBINT Draw_Shape(void *graphics, REBSER *block, REBSER *args)
/*
***********************************************************************/
{
	REBCNT index = 0;
	REBINT cmd;
	//REBSER *args = 0;  // cannot be done here a GC problem
	REBVAL *arg;
	REBCNT nargs;
	REBINT rel;
	do {
		cmd = Reb_Dialect(DIALECTS_DRAW, block, &index, &args);

		if (cmd == 0) return 0;
		if (cmd < 0) {
//			Reb_Print("ERROR: %d, Index %d", -cmd, index);
			return -((REBINT)index+1);
		}
//		else
//			Reb_Print("SHAPE: Cmd %d, Index %d, Args %m", cmd, index, args);

		arg = BLK_HEAD(args);
		nargs = SERIES_TAIL(args);
//		Reb_Print("Number of args: %d", nargs);

		rel = 0;

		switch (cmd) {
			case DW_ARC_LIT:
				rel = 1;
			case DW_ARC:
				{
					REBDEC r;
					REBPAR* p = &ARG_PAIR(0);
					REBINT sweep = 4;
					REBINT large = 6;
					if (ARG_WORD(4) == DW_LARGE){
						sweep = 6;
						large = 4;
					}
					if (IS_NONE(arg+2))
						r = (fabs(p->x) + fabs(p->y)) / 2;
					else
						r = ARG_DECIMAL(2);

					agg_path_arc(graphics, rel, p, r, (IS_NONE(arg+3)) ? r : ARG_DECIMAL(3), (IS_NONE(arg+5)) ? 0 : ARG_DECIMAL(5), DW_SWEEP == ARG_WORD(sweep), DW_LARGE == ARG_WORD(large));
					break;
				}
			case DW_CLOSE:
				agg_path_close(graphics);
				break;
			case DW_CURV_LIT:
				rel = 1;
			case DW_CURV:
				{
					REBCNT n = 0;
					for (n = 0; n < nargs; n+=2) {
						if (IS_PAIR(arg+n) && IS_PAIR(arg+n+1))
							agg_path_curv(graphics, rel, &ARG_PAIR(n), &ARG_PAIR(n+1));
					}
					break;
				}
			case DW_CURVE_LIT:
				rel = 1;
			case DW_CURVE:
				{
					REBCNT n = 0;
					for (n = 0; n < nargs; n+=3) {
						if (IS_PAIR(arg+n) && IS_PAIR(arg+n+1) && IS_PAIR(arg+n+2))
							agg_path_curve(graphics, rel, &ARG_PAIR(n), &ARG_PAIR(n+1), &ARG_PAIR(n+2));
					}
					break;
				}
				break;
			case DW_HLINE_LIT:
				rel = 1;
			case DW_HLINE:
				if (IS_INTEGER(arg))
					agg_path_hline(graphics, rel, VAL_INT32(arg));
				else if (IS_DECIMAL(arg))
					agg_path_hline(graphics, rel, VAL_DECIMAL(arg));
				break;
			case DW_LINE_LIT:
				rel = 1;
			case DW_LINE:
				{
					REBCNT n = 0;
					for (n = 0; n < nargs; n++) {
						agg_path_line(graphics, rel, &ARG_PAIR(n));
					}
					break;
				}
			case DW_MOVE_LIT:
				rel = 1;
			case DW_MOVE:
				{
					REBCNT n = 0;
					for (n = 0; n < nargs; n++) {
						if(n) agg_path_line(graphics, rel, &ARG_PAIR(n));
						agg_path_move(graphics, rel, &ARG_PAIR(n));
					}
					break;
				}
			case DW_QCURV_LIT:
				rel = 1;
			case DW_QCURV:
				if (IS_PAIR(arg))
					agg_path_qcurv(graphics, rel, &ARG_PAIR(0));
				break;
			case DW_QCURVE_LIT:
				rel = 1;
			case DW_QCURVE:
				{
					REBCNT n = 0;
					for (n = 0; n < nargs; n+=2) {
						if (IS_PAIR(arg+n) && IS_PAIR(arg+n+1))
							agg_path_qcurve(graphics, rel, &ARG_PAIR(n), &ARG_PAIR(n+1));
					}
					break;
				}
			case DW_VLINE_LIT:
				rel = 1;
			case DW_VLINE:
				if (IS_INTEGER(arg))
					agg_path_vline(graphics, rel, VAL_INT32(arg));
				else if (IS_DECIMAL(arg))
					agg_path_vline(graphics, rel, VAL_DECIMAL(arg));
				break;
		}

	} while (TRUE);
}

/***********************************************************************
**
*/	REBINT Draw_Gob(void *graphics, REBSER *block, REBSER *args)
/*
**		Handles all commands for the DRAW dialect as specified
**		in the system/dialects/draw object.
**
**		This function calls the REBOL_Dialect interpreter to
**		parse the dialect and build and return the command number
**		(the index offset in the draw object above) and a block
**		of arguments. (For now, just a REBOL block, but this could
**		be changed to isolate it from changes in REBOL's internals).
**
**		Each arg will be of the specified datatype (given in the
**		dialect) or NONE when no argument of that type was given
**		and this code must determine the proper default value.
**
**		If the cmd result is zero, then it is either the end of
**		the block, or an error has occurred. If the error value
**		is non-zero, then it was an error.
**
***********************************************************************/
{
//	REBSER *block;
	REBCNT index = 0;
	REBINT cmd;
//	REBSER *args = 0; // cannot be done here a GC problem
	REBVAL *arg;
	REBCNT nargs;

	// default values
	REBPAR zero_pair = {0,0};
	REBPAR size_pair;
	REBPAR center_pair;

	agg_get_size(graphics, &size_pair);
	center_pair.x = size_pair.x / 2;
	center_pair.y = size_pair.y / 2;

	do {
		cmd = Reb_Dialect(DIALECTS_DRAW, block, &index, &args);

		if (cmd == 0) return 0;
		if (cmd < 0) {
//			Reb_Print("ERROR: %d, Index %d", -cmd, index);
			return -((REBINT)index+1);
		}
//		else
//			Reb_Print("DRAW: Cmd %d, Index %d, Args %m", cmd, index, args);

		arg = BLK_HEAD(args);
		nargs = SERIES_TAIL(args);
//		Reb_Print("Number of args: %d", nargs);

#ifdef ENABLE_DRAW
		switch (cmd) {

		case DW_TYPE_SPEC:
			if (IS_BLOCK(arg)) {
				REBINT result = Draw_Gob(graphics,ARG_BLOCK(0), args);
				if (result < 0) return result;
			}
			break;

		//	anti-alias:		[logic!]
		case DW_ANTI_ALIAS:
			agg_anti_alias(graphics, IS_LOGIC(arg) && ARG_LOGIC(0));
			break;

		//	arc:			[pair! pair! decimal! decimal! word! decimal! word!]
		case DW_ARC:
			agg_arc(graphics, IS_NONE(arg) ? &zero_pair: &ARG_PAIR(0), IS_NONE(arg+1) ? &size_pair : &ARG_PAIR(1), IS_NONE(arg+2) ? 0 : ARG_DECIMAL(2), IS_NONE(arg+3) ? 90 : ARG_DECIMAL(3), DW_CLOSED == ARG_WORD(4));
			break;

		//	arrow:			[tuple! pair!]
		case DW_ARROW:
			agg_arrow(graphics, IS_TUPLE(arg) ? ARG_TUPLE(0) : NULL, &ARG_PAIR(1));
			break;

		//	box:			[pair! pair! decimal!]
		case DW_BOX:
			agg_box(graphics, IS_NONE(arg) ? &zero_pair: &ARG_PAIR(0), IS_NONE(arg+1) ? &size_pair : &ARG_PAIR(1), ARG_DECIMAL(2));
			break;

		//	circle:			[pair! decimal! decimal!]
		case DW_CIRCLE:
			{
				REBDEC r = IS_NONE(arg+1) ? min(center_pair.x,center_pair.y): ARG_DECIMAL(1);
				agg_circle(graphics, IS_NONE(arg) ? &center_pair: &ARG_PAIR(0), r, (IS_NONE(arg+2)) ? r : ARG_DECIMAL(2));
			}
			break;

		//	clip:			[pair! pair! logic!]
		case DW_CLIP:
			if (!IS_PAIR(arg) || !IS_PAIR(arg+1))
				agg_clip(graphics, &zero_pair, &size_pair);
			else
				agg_clip(graphics, &ARG_PAIR(0), &ARG_PAIR(1));
			break;

		//	curve:			[* pair!] ;shared with SHAPE command
		case DW_CURVE:
			switch (nargs){
				case 3:
					agg_curve3(graphics, &ARG_PAIR(0), &ARG_PAIR(1), &ARG_PAIR(2));
					break;
				case 4:
					agg_curve4(graphics, &ARG_PAIR(0), &ARG_PAIR(1), &ARG_PAIR(2), &ARG_PAIR(3));
					break;
				default:
					{
						REBPAR tr = {size_pair.x, 0};
						REBPAR bl = {0, size_pair.y};
						agg_curve4(graphics, &zero_pair, &bl, &tr, &size_pair);
					}
			}
			break;

		//	effect:			[pair! pair! block!]
		case DW_EFFECT:
			if (IS_BLOCK(arg+2))
				agg_effect(graphics, IS_NONE(arg) ? &zero_pair : &ARG_PAIR(0), IS_NONE(arg+1) ? &size_pair : &ARG_PAIR(1), ARG_BLOCK(2));
			break;

		//	ellipse:		[pair! pair!]
		case DW_ELLIPSE:
			agg_ellipse(graphics, IS_NONE(arg) ? &zero_pair : &ARG_PAIR(0), IS_NONE(arg+1) ? &size_pair : &ARG_PAIR(1));
			break;

		//	fill-pen:		[tuple! image! logic!]
		case DW_FILL_PEN:
			if (IS_TUPLE(arg)) {
				//plain fill
				agg_fill_pen(graphics, ARG_TUPLE(0));
				break;
			}
			if (IS_IMAGE(arg+1)) {
				//image fill
				agg_fill_image_pen(graphics, ARG_IMAGE(1));
				break;
			}
			agg_fill_pen(graphics, NULL);
			break;

		//	fill-rule:		[word!]
		case DW_FILL_RULE:
			agg_fill_rule(graphics, ARG_WORDS(0,DW_NON_ZERO,DW_EVEN_ODD));
			break;

		//	gamma:			[decimal!]
		case DW_GAMMA:
			agg_gamma(graphics, ARG_DECIMAL(0));
			break;

		//	grad-pen:		[word! word! pair! logic! decimal! decimal! decimal! decimal! decimal! block!]
		case DW_GRAD_PEN:
			//[word! word! pair! logic! block! * decimal! * tuple!]
			if (IS_NONE(arg) && IS_NONE(arg+1) && IS_NONE(arg+2) && IS_NONE(arg+4) && IS_NONE(arg+5) && IS_NONE(arg+6) && IS_NONE(arg+7) && IS_NONE(arg+8) && IS_NONE(arg+9)) {
					//turn off the grad pen
					agg_reset_gradient_pen(graphics);
			} else {
				unsigned char colors[256*4+1] = {2, 0,0,0,0, 0,0,0,0, 255,255,255,0}; //max number of color tuples is 256 + one length information char
				REBDEC offsets[256] = {0.0 , 0.0, 1.0};

				if (IS_BLOCK(arg+9)) {
					//gradient fill
					REBCNT i,j,k;

					REBSER *blk = ARG_BLOCK(9);
					REBVAL *slot = BLK_HEAD(blk);
					REBCNT len = SERIES_TAIL(blk);

					for (i = 0, j = 1, k = 5;i<len;i++){
						if (IS_DECIMAL(slot+i) || IS_INTEGER(slot+i)) {

							offsets[j] = IS_DECIMAL(slot+i) ? VAL_DECIMAL(slot+i) : VAL_INT32(slot+i);

							//do some validation
							offsets[j] = min(max(offsets[j], 0.0), 1.0);
							if (j != 1 && offsets[j] < offsets[j-1])
								offsets[j] = offsets[j-1];
							if (j != 1 && offsets[j] == offsets[j-1])
								offsets[j-1]-= 0.0000000001;
							j++;

						} else if (IS_TUPLE(slot+i)){
							COPY_MEM(&colors[k], VAL_TUPLE(slot+i), 4);
							k+=4;
						}
					}
					if (j == 1) offsets[0] = -1;
					colors[0] = max (2, (k - 5) / 4);
				}

				agg_gradient_pen(
						graphics,
						IS_NONE(arg) ? DW_LINEAR - DW_RADIAL : ARG_WORDS(0,DW_RADIAL,DW_CUBIC), //type
						IS_NONE(arg+2) ? &zero_pair : &ARG_PAIR(2),								//position
						IS_NONE(arg+4) ? 0.0 : ARG_DECIMAL(4),									//rng begin
						IS_NONE(arg+5) ? 640.0 : ARG_DECIMAL(5),								//rng end
						IS_NONE(arg+6) ? 0.0 : ARG_DECIMAL(6),									//angle
						IS_NONE(arg+7) ? 1.0 : ARG_DECIMAL(7),									//scale X
						IS_NONE(arg+8) ? 1.0 : ARG_DECIMAL(8),									//scale Y
						colors,																	//colors
						offsets,																//offsets
						IS_NONE(arg+1) ? 0 : ARG_WORDS(1,DW_NORMAL,DW_REFLECT)					//mode
					);
			}
			break;

		//	invert-matrix:	[]
		case DW_INVERT_MATRIX:
			agg_invert_matrix(graphics);
			break;

		//	image:			[image! tuple! word! word! integer! integer! integer! integer! * pair!]
		case DW_IMAGE:
			{
				REBINT border = 3, mode = 2, pw,ph;
				REBYTE* keycolor =  ARG_TUPLE(1);
				if (IS_NONE(arg)) break;

				if (IS_NONE(arg+1))
					keycolor[3] = 255;

				if (ARG_WORD(2) == DW_BORDER){
					border = 2;
					mode = 3;
				}

				switch (nargs){
					case 8:
					case 9://at offset
						if (ARG_IMAGE(0)){
							agg_image(graphics, ARG_IMAGE(0), &ARG_PAIR(8), keycolor, DW_BORDER == ARG_WORD(border));
						}
						break;
					case 10:
						if (IS_NONE(arg+6))
							pw = ARG_PAIR(9).x - ARG_PAIR(8).x;
						else
							pw =  ARG_INTEGER(6);
						if (IS_NONE(arg+7))
							ph = ARG_PAIR(9).y - ARG_PAIR(8).y;
						else
							ph =  ARG_INTEGER(7);

						agg_image_perspective(graphics, ARG_IMAGE(0), &ARG_PAIR(8),  keycolor, DW_BORDER == ARG_WORD(border), ARG_WORDS(mode,DW_NORMAL,DW_REFLECT), ARG_INTEGER(4), ARG_INTEGER(5), pw, ph, &ARG_PAIR(9), &ARG_PAIR(9) , &ARG_PAIR(9) , nargs);
						break;
					case 11:
						if (IS_NONE(arg+6))
							pw = ARG_PAIR(10).x - ARG_PAIR(8).x;
						else
							pw =  ARG_INTEGER(6);
						if (IS_NONE(arg+7))
							ph = ARG_PAIR(10).y - ARG_PAIR(8).y;
						else
							ph =  ARG_INTEGER(7);

						agg_image_perspective(graphics, ARG_IMAGE(0), &ARG_PAIR(8), keycolor, DW_BORDER == ARG_WORD(border), ARG_WORDS(mode,DW_NORMAL,DW_REFLECT), ARG_INTEGER(4), ARG_INTEGER(5), pw, ph, &ARG_PAIR(9),&ARG_PAIR(10), &ARG_PAIR(10), nargs);
						break;
					case 12:
						if (IS_NONE(arg+6))
							pw = ARG_PAIR(10).x - ARG_PAIR(8).x;
						else
							pw =  ARG_INTEGER(6);
						if (IS_NONE(arg+7))
							ph = ARG_PAIR(10).y - ARG_PAIR(8).y;
						else
							ph =  ARG_INTEGER(7);
						agg_image_perspective(graphics, ARG_IMAGE(0), &ARG_PAIR(8), keycolor, DW_BORDER == ARG_WORD(border), ARG_WORDS(mode,DW_NORMAL,DW_REFLECT), ARG_INTEGER(4), ARG_INTEGER(5), pw, ph, &ARG_PAIR(9),&ARG_PAIR(10),&ARG_PAIR(11), nargs);
						break;
				}
			}
			break;

		//	image-filter:	[word! word! decimal!]
		case DW_IMAGE_FILTER:
			{
				REBINT type = 0, mode = 1;

				if (ARG_WORD(0) == DW_RESAMPLE){
						type = 1;
						mode = 0;
				}

				agg_image_filter(graphics, ARG_WORDS(type,DW_NEAREST,DW_GAUSSIAN),ARG_WORD(mode) == DW_RESAMPLE, IS_NONE(arg+2) ? 1.0 : ARG_DECIMAL(2));
			}
			break;

		//	line:			[* pair!] ;shared with SHAPE command
		case DW_LINE:
			if (nargs){
				REBINT n = 0;
				for (n = 0; nargs > 1; nargs--, n++) {
					agg_line(graphics, &ARG_PAIR(n), &ARG_PAIR(n+1));
				}
			} else {
				agg_line(graphics, &zero_pair, &size_pair);
			}
			break;

		//	line-cap:		[word!]
		case DW_LINE_CAP:
			agg_line_cap(graphics, ARG_WORDS(0,DW_BUTT,DW_ROUNDED));
			break;

		//	line-join:		[word!]
		case DW_LINE_JOIN:
			agg_line_join(graphics, ARG_WORDS(0,DW_MITER,DW_BEVEL));
			break;

		//	line-pattern:	[logic! tuple! * decimal!]
		case DW_LINE_PATTERN:
			if (nargs > 3){
				REBCNT n = 0;
				REBDEC *patterns = (REBDEC*) MAKE_MEM((nargs-1) * sizeof(REBDEC)) ;
				patterns[0] = (REBDEC)nargs-2;
				for (n = 2; n < nargs; n++) {
					if (IS_DECIMAL(arg+n))
						patterns[n-1] = ARG_DECIMAL(n);
					else
						break;
				}

				agg_line_pattern(graphics, IS_TUPLE(arg+1) ? ARG_TUPLE(1) : NULL, patterns);
			} else {
				agg_line_pattern(graphics, 0, 0);
			}
			break;

		//	line-width:		[decimal! word!]
		case DW_LINE_WIDTH:
			agg_line_width(graphics,  ARG_DECIMAL(0), ARG_WORD(1) == DW_FIXED);
			break;

		//	matrix:			[block!]
		case DW_MATRIX:
			agg_matrix(graphics, ARG_BLOCK(0));
			break;

		//	pen:			[tuple! image! logic!]
		case DW_PEN:
			agg_pen(
				graphics,
				IS_TUPLE(arg) ? ARG_TUPLE(0) : NULL,
				IS_IMAGE(arg+1) ? ARG_IMAGE(1) : NULL
			);
			break;

		//	polygon:		[* pair!]
		case DW_POLYGON:
			if (nargs){
				REBINT n = 0;
				if (nargs > 1){
					while (nargs--){
						if (n){
							agg_add_vertex(graphics, ARG_PAIR(n).x, ARG_PAIR(n).y);
						} else {
							agg_begin_poly(graphics, ARG_PAIR(n).x, ARG_PAIR(n).y);
						}
						n++;
					}
					agg_end_poly(graphics);
				}
			} else {
				agg_begin_poly(graphics, 0, 0);
				agg_add_vertex(graphics, size_pair.x, 0);
				agg_add_vertex(graphics, size_pair.x, size_pair.y);
				agg_add_vertex(graphics, 0, size_pair.y);
				agg_end_poly(graphics);
			}
			break;

		//	push:			[block!]
		case DW_PUSH:
			agg_push_matrix(graphics);
			if (IS_BLOCK(arg)) {
				REBINT result = Draw_Gob(graphics,ARG_BLOCK(0), args);
				if (result < 0) return result;
			}
			agg_pop_matrix(graphics);
			break;

		//	reset-matrix:	[]
		case DW_RESET_MATRIX:
			agg_reset_matrix(graphics);
			break;

		//	rotate:			[decimal!]
		case DW_ROTATE:
			agg_rotate(graphics, ARG_DECIMAL(0));
			break;

		//	scale:			[decimal! decimal!]
		case DW_SCALE:
			agg_scale(graphics, ARG_DECIMAL(0), ARG_DECIMAL(1));
			break;

		//	shape:			[block!]
		case DW_SHAPE:
			if (IS_BLOCK(arg)) {
				REBINT result;
				agg_path_open(graphics);
				result = Draw_Shape(graphics, ARG_BLOCK(0), args);
				if (result < 0) return result;
				agg_path_close(graphics);
			}
			//agg_shape(graphics, ARG_BLOCK(0));
			break;

		//	skew:			[decimal!]
		case DW_SKEW:
			agg_skew(graphics, ARG_DECIMAL(0), ARG_DECIMAL(1));
			break;

		//	spline:			[integer! word! * pair!]
		case DW_SPLINE:
			if (nargs > 3){
				REBINT n = 2;
				nargs-=2; //skip first two args
				while (nargs--){
					if (n == 2){
						agg_begin_poly(graphics, ARG_PAIR(n).x, ARG_PAIR(n).y);
					} else {
						agg_add_vertex(graphics, ARG_PAIR(n).x, ARG_PAIR(n).y);
					}
					n++;
				}
				agg_end_spline(graphics, ARG_INTEGER(0), DW_CLOSED == ARG_WORD(1));
			} else {
				agg_begin_poly(graphics, 0, center_pair.y);
				agg_add_vertex(graphics, center_pair.x / 2, size_pair.y);
				agg_add_vertex(graphics, size_pair.x - (size_pair.x / 3), 0);
				agg_add_vertex(graphics, size_pair.x, center_pair.y);
				agg_end_spline(graphics, 16,0);
			}
			break;

		//	text:			[word! pair! pair! block!]
		case DW_TEXT:
			if (IS_BLOCK(arg+3)) {
				REBINT result = agg_text(graphics, DW_VECTORIAL == ARG_WORD(0), &ARG_PAIR(1), IS_NONE(arg+2) ? NULL : &ARG_PAIR(2), ARG_BLOCK(3));
				if (result < 0) return result;
			}
			break;

		//	transform:		[decimal! pair! decimal! decimal! pair!]
		case DW_TRANSFORM:
			agg_transform(graphics, ARG_DECIMAL(0), &ARG_PAIR(1), ARG_DECIMAL(2), ARG_DECIMAL(3), &ARG_PAIR(4));
			break;

		//	translate:		[pair!]
		case DW_TRANSLATE:
			agg_translate(graphics, &ARG_PAIR(0));
			break;

		//	triangle:		[pair! pair! pair! tuple! tuple! tuple! decimal!]
		case DW_TRIANGLE:
			{
				REBPAR p1 = (IS_NONE(arg)) ? zero_pair : ARG_PAIR(0);
				REBPAR p2 = (IS_NONE(arg+1)) ? size_pair : ARG_PAIR(1);
				REBYTE b[4] = {0,0,0,0};
				REBYTE* pb = b;
				if (IS_NONE(arg+2)) {
					ARG_PAIR(2).x = p1.x;
					ARG_PAIR(2).y = p2.y;
				}
				if (IS_NONE(arg+3)) pb = 0;
				agg_triangle(graphics, &p1, &p2, &ARG_PAIR(2), !pb ? pb : ARG_TUPLE(3), IS_NONE(arg+4) ? pb : ARG_TUPLE(4), IS_NONE(arg+5) ? pb : ARG_TUPLE(5), ARG_DECIMAL(6));
				break;
			}
		}

#endif // ENABLE_DRAW

	} while (TRUE);
}
